home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / db / esm-3.1 / esm-3 / usr / local / sm / src / client / trans / serverTransPool.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-05  |  17.0 KB  |  699 lines

  1. #ifndef __serverTransPool_C__
  2. #define __serverTransPool_C__
  3. /*
  4.  *   $RCSfile: serverTransPool.C,v $  
  5.  *   $Revision: 1.1.1.1 $  
  6.  *   $Date: 1996/05/04 21:55:30 $      
  7.  */ 
  8. /**********************************************************************
  9. * EXODUS Database Toolkit Software
  10. * Copyright (c) 1991 Computer Sciences Department, University of
  11. *                    Wisconsin -- Madison
  12. * All Rights Reserved.
  13. *
  14. * Permission to use, copy, modify and distribute this software and its
  15. * documentation is hereby granted, provided that both the copyright
  16. * notice and this permission notice appear in all copies of the
  17. * software, derivative works or modified versions, and any portions
  18. * thereof, and that both notices appear in supporting documentation.
  19. *
  20. * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
  21. * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.  
  22. * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
  23. * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  24. *
  25. * The EXODUS Project Group requests users of this software to return 
  26. * any improvements or extensions that they make to:
  27. *
  28. *   EXODUS Project Group 
  29. *     c/o David J. DeWitt and Michael J. Carey
  30. *   Computer Sciences Department
  31. *   University of Wisconsin -- Madison
  32. *   Madison, WI 53706
  33. *
  34. *     or exodus@cs.wisc.edu
  35. *
  36. * In addition, the EXODUS Project Group requests that users grant the 
  37. * Computer Sciences Department rights to redistribute these changes.
  38. **********************************************************************/
  39.  
  40. #include "Pool.h"
  41. #include "resources.h"
  42. #include "sysdefs.h"
  43. #include "ess.h"
  44. #include "checking.h"
  45. #include "trace.h"
  46. #include "error.h"
  47. #include "io.h"
  48. #include "page.h"
  49. #include "list.h"
  50. #include "object.h"
  51. #include "pool.h"
  52. #include "tid.h"
  53. #include "bf.h"
  54. #include "chunk.h"
  55. #include "bf_macro.h"
  56. #include "lock.h"
  57. #include "scan.h"
  58. #include "load.h"
  59. #include "msgdefs.h"
  60. #include "trans.h"
  61. #include "clog.h"
  62. #include "distr.h"
  63. #include "sm_state.h"
  64. #include "serverinfo.h"
  65. #include "trans_funcs.h"
  66. #include "msg_funcs.h"
  67. #include "clog_extfuncs.h"
  68. #include "trans_globals.h"
  69. #include "bf_intfuncs.h"
  70. #include "bf_extfuncs.h"
  71. #include "fi_extfuncs.h"
  72. #include "io_extfuncs.h"
  73. #include "scan.h"
  74. #include "sm_intfuncs.h"
  75. #include "sm_globals.h"
  76.  
  77.  
  78. void 
  79. SERVERTRANSREC:: Init() {
  80.     this->ReInit();
  81.     initializeListElement( &(this->participants), this);
  82.     initializeListElement( &(this->transList),this);
  83. };
  84. void 
  85. SERVERTRANSREC:: ReInit() {
  86.     this->tid = NULL_TID;
  87.     this->serverTransState = T_INACTIVE;
  88.     this->serverInfo = NULL;
  89.     this->transRec = NULL;
  90. };
  91. LISTELEMENT *
  92. SERVERTRANSREC:: listlocation(int unique) {
  93.     TRPRINT(TR_TRANS, TR_LEVEL_1, (" ", unique));
  94.     SM_ASSERT(LEVEL_1, (unique == SERVERTRANS_POOL));
  95.     return &(this->participants);
  96. }
  97.  
  98. Pool<SERVERTRANSREC>          *serverTransPool;
  99.  
  100. void
  101. trans_Shutdown()
  102. {
  103.     delete serverTransPool;
  104.     serverTransPool = NULL;
  105.     TransRec.clientTransState = T_INACTIVE;
  106. }
  107.  
  108.  int
  109. initTrans ()
  110. {
  111.     TRACE(TR_TRANS, TR_LEVEL_1);
  112.  
  113.     TransRec.clientTid = NULL_TID;
  114.     TransRec.clientTransState = T_INACTIVE;
  115.     initializeList( &(TransRec.userDescList) );
  116.     initializeList( &(TransRec.pageHashList) );
  117.     initializeList( &(TransRec.bufGroupList) );
  118.     initializeList( &(TransRec.lockHeaderList) );
  119.     initializeList( &(TransRec.participants) );
  120.     INIT_TRANSREC_MAGIC( &TransRec );
  121.  
  122.     serverTransPool = new Pool<SERVERTRANSREC> ( "serverTrans", 
  123.         SERVERTRANS_POOL, ServerTransPoolSize, POOL_NOMORE_GETMORE );
  124.     if(serverTransPool == NULL) {
  125.         SM_ERROR(TYPE_SYS, esmMALLOCFAILED);
  126.         return esmFAILURE;
  127.     }
  128.  
  129.     /* 
  130.     serverTransPool->Stats(stderr);
  131.     */
  132.  
  133.     /* Record whether logging has been turned off for any file */
  134.     fi_MarkLoggingOff();
  135.  
  136.     /* hints are not valid between transactions */
  137.     fi_InvalidateHints();
  138.  
  139.     return esmNOERROR;
  140. }
  141.  
  142. static BOOL
  143. ClearLogTailPage( SERVERTRANSREC *stl )
  144. {
  145.     LOGINFO *logInfo = &(stl->serverInfo->logInfo);
  146.  
  147. #ifdef DEBUG
  148.     if (logInfo->tailBuffer != NULL) {
  149.         SM_ASSERT(LEVEL_1, 
  150.         (logInfo->tailBuffer->hashList.hashPid.volid == logInfo->volid));
  151.  
  152.         SM_ASSERT(LEVEL_1, PAGE_IS_CLEAN(logInfo->tailBuffer));
  153.     }
  154.     TRPRINT(TR_LOG, TR_LEVEL_1, ("LOG %d not dirty", logInfo->volid));
  155.  
  156. #endif DEBUG
  157.     logInfo->tailBuffer = NULL;
  158.  
  159.     return FALSE;
  160. }
  161.  
  162.  
  163.  
  164. SERVERTRANSREC *
  165. addTransServerInfo(
  166.     TRANSREC *transRec, 
  167.     SERVERINFO *serverInfo
  168. )
  169. {
  170.     SERVERTRANSREC *stl;
  171.  
  172.     TRPRINT(TR_TRANS, TR_LEVEL_1, 
  173.         ("Adding server %s to trans", serverInfo->hostName));
  174.  
  175.     stl = serverTransPool->Get();
  176.     stl->serverInfo = serverInfo;
  177.     stl->transRec = transRec;
  178.     transRec->numParticipants ++;
  179.     listEnq(&(transRec->participants), &(stl->participants));
  180.     listEnq(&(serverInfo->transList), &(stl->transList));
  181.  
  182.     return stl;
  183. }
  184. void
  185. removeServerTransInfo(TRANSREC *transRec, void *msg)
  186. {
  187.     MESSAGE                        *message = (MESSAGE *)msg;
  188.     SERVERTRANSREC                 *stl;
  189.  
  190.     TRPRINT(TR_TRANS, TR_LEVEL_1, ("clearing servers from trans"));
  191.  
  192.     while((stl = (SERVERTRANSREC *)listDeq(&(transRec->participants)))!=NULL) {
  193.         transRec->numParticipants --;
  194.  
  195.         if((message != NULL) && (stl->serverTransState == T_ACTIVE)) {
  196.                 TRPRINT(TR_TRANS, TR_LEVEL_1, 
  197.                     ("sending message type %d to server %s",
  198.                     message->header.type, stl->serverInfo->hostName));
  199.             message->header.params.in.tid = stl->tid;
  200.  
  201.             if (callServer(stl->serverInfo, message, NULL, 0 ) != esmNOERROR){
  202.                 /*
  203.                  *    The only way callServer could fail is if the server
  204.                  *    died, or if the transaction is already aborted.  In
  205.                  *    either case, the transaction will be aborted, so do
  206.                  *    nothing special on error
  207.                  */
  208.             }
  209.         }
  210.         /* remove this from the list of transactions considered
  211.          * active on this server
  212.          */
  213.         listRemove(&(stl->transList));
  214.         serverTransPool->Put( stl );
  215.  
  216.     }
  217.     transRec->clientTransState = T_INACTIVE;    
  218. }
  219.  
  220. void
  221. endTransForAllServers(
  222.     TRANSREC     *transRec,
  223.     int            messageType
  224. )
  225. {
  226.     MESSAGE                        message;
  227.     message.header.type = messageType;
  228.     message.header.replyRequested = TRUE;
  229.     removeServerTransInfo(transRec, &message);
  230. }
  231.  
  232.  void
  233. ForEachServerInTrans(
  234.     TRANSREC     *transRec,
  235.     int            nargs,
  236.     void        *f,
  237.     void        *arg1,
  238.     void        *arg2,
  239.     void        *arg3,
  240.     void        *arg4,
  241.     void        *arg5,
  242.     void        *arg6
  243. )
  244. {
  245.     FOREACHFUNC    func = (FOREACHFUNC)f;
  246.     SERVERTRANSREC *stl;
  247.  
  248.     TRPRINT(TR_TRANS, TR_LEVEL_1, ("sending to servers"));
  249.     SM_ASSERT(LEVEL_1, (nargs <= 7));
  250.     SM_ASSERT(LEVEL_1, (nargs >= 1));
  251.  
  252.     for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants));
  253.         stl!=NULL;
  254.         stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->participants)) ) {
  255.  
  256.             if ((*func)(stl, arg1, arg2, arg3, arg4, arg5, arg6))
  257.                 break; /* stop looking if found */
  258.     }
  259. }
  260.  
  261.  void
  262. ForEachTrans(
  263.     int        nargs,
  264.     void    *func,
  265.     void    *arg1,
  266.     void    *arg2,
  267.     void    *arg3
  268. {
  269.     TRANSREC        *transRec = findTransRec(getLocalTid());
  270.  
  271.     SM_ASSERT(LEVEL_1, (nargs <= 4));
  272.     SM_ASSERT(LEVEL_1, (nargs >= 1));
  273.  
  274.     /* TODO: go through all trans recs, using the 
  275.      * generic ForEach function, which looks at nargs, but
  276.      * passes only arg1, ... to the function.
  277.      */
  278.     (void) (*((FOREACHFUNC)func))(transRec, arg1, arg2, arg3);
  279. }
  280.  
  281.  
  282.  int
  283. commandTrans (
  284.     TRANSREC    *transRec,
  285.     COMMAND        command
  286. )
  287. {
  288.     MESSAGE            message;
  289.     int             error;
  290.     TRACE(TR_TRANS, TR_LEVEL_1);
  291.  
  292.     /*
  293.      *      We can proceed directly to make the call to the 
  294.      *      coordinator as everything else should have been
  295.      *      done at prepare time
  296.      */
  297.     message.header.replyRequested = TRUE;
  298.     message.header.type = CLIENT_COMMAND;
  299.     message.header.params.in.tid = transRec->coordTid;
  300.     message.body.command.command = command;
  301.     /*
  302.      *    TODO - mention whether logging was turned on. ??
  303.      */
  304.     /* message.body.trans.loggingOn = LogInfo.loggingOn; */
  305.  
  306.     error = callServer(transRec->coordInfo, &message, NULL, 0 );
  307.  
  308.     /*
  309.         The server's replies to a commandTrans are :
  310.             
  311.         esmTRANSDISABLED, (not done - i'm not done with recovery - 
  312.             try later)
  313.         esmBADTRANSID, (i don't know about this trans so it must
  314.             have been done already) 
  315.         esmNOTTRANSMASTER, (you can't tell me to do this so I won't - 
  316.             someone else must)
  317.         esmBADCOMMAND (i didn't understand you so it's not been done
  318.             internal error)
  319.             
  320.         esmTRANSNOTPREPARED so i ignored this commit request -
  321.             fail but don't locally do anything
  322.  
  323.         esmTRANSABORTED transaction was aborted during commit.
  324.  
  325.         esmNOERROR (abort/commit done)
  326.  
  327.         If the server got disconnected, the client code can return
  328.             esmSERVERDIED or esmNOTCONNECTED (doubtful):
  329.             assume that it was not done and retry
  330.     */
  331.  
  332.     if(error == esmNOERROR)
  333.         return esmNOERROR;
  334.         
  335.     switch(sm_errno) {
  336.  
  337.     case esmSERVERDIED:
  338.     case esmNOTCONNECTED:
  339.     case esmTRANSDISABLED:
  340.         /* might want to try again later */
  341.         break; /* failed; leave tx active */
  342.  
  343.     case esmTRANSABORTED:
  344.     case esmBADTRANSID:
  345.         return esmNOERROR;
  346.  
  347.     case esmNOTTRANSMASTER:
  348.         /* This might happen when a client crashes and a new client
  349.          * comes up to tell the coordinator to finish the tx
  350.          * TODO: We need to fix this on the server.
  351.          */
  352.         SM_ERROR(TYPE_CRASH, sm_errno);
  353.  
  354.     case esmTRANSNOTPREPARED:
  355.         break; /* failed: leave tx active */
  356.  
  357.     case esmBADCOMMAND: /* internal (protocol) error */
  358.     default: /* don't know what this situation is ! */
  359.         SM_ERROR(TYPE_FATAL, sm_errno);
  360.     }
  361.     return esmFAILURE;
  362. }
  363.  
  364. BEGIN_EXTERNC
  365. extern  void sm_EndAllIndexLoads(TID);
  366. extern  void sm_CloseAllLoadsAndScans();
  367. extern  void sm_ReleaseAllUserDesc();
  368. END_EXTERNC
  369.  
  370. static void
  371. endTrans(int how, TRANSREC *transRec)
  372. {
  373.     sm_EndAllIndexLoads(transRec->clientTid);
  374.     sm_CloseAllLoadsAndScans();
  375.     sm_ReleaseAllUserDesc();
  376.  
  377.     closeBufferGroups();
  378.     switch(how) {
  379.     /* kludge - overload the transaction states to indicate which way we are ending the tx */
  380.     case T_ABORT:
  381.         bf_FlushAll( TRUE /*2nd arg doesn't matter */ ); /* discard */
  382.         break;
  383.     case T_COMMIT:
  384.     case T_PREPARED:
  385.         clog_ForceAllLogs(transRec);
  386.         bf_FlushAll( FALSE, TRUE ); /* don't discard, skip temp vol pages */
  387.         break;
  388.     default: 
  389.         /* should not be possible */
  390.         SM_ERROR(TYPE_FATAL, esmINTERNAL);
  391.     }
  392.     ForEachServerInTrans( transRec, 1, ClearLogTailPage );
  393.  
  394. #ifdef DEBUG
  395.     if(how == T_ABORT) 
  396.         BF_AssertPageHashTableEmpty();
  397. #endif DEBUG
  398.  
  399.     /* Record whether logging has been turned off for any file */
  400.     fi_MarkLoggingOff();
  401.  
  402.     /* hints are not valid between transactions */
  403.     fi_InvalidateHints();
  404. }
  405.  
  406.  
  407.  
  408.  int
  409. commitTrans (
  410.     TRANSREC    *transRec
  411. )
  412. {
  413.     MESSAGE                        message;
  414.     SERVERINFO                    *serverInfo;
  415.     int                            error;
  416.     SERVERTRANSREC                *stl;
  417.  
  418.     TRACE(TR_TRANS, TR_LEVEL_1);
  419.  
  420.     endTrans(T_COMMIT, transRec);
  421.  
  422.     /*
  423.      *    setup the commit transaction message.
  424.      *    mention whether logging was turned on.
  425.      */
  426.     message.header.type = COMMIT_TRANS;
  427.     message.header.replyRequested = TRUE;
  428.  
  429.     if (transRec->numParticipants >= 1) {
  430.         /*
  431.          *    there can only be a single server involved
  432.          *    else, either prepareTrans or commandTrans
  433.          *    would have benn called
  434.          */
  435.         SM_ASSERT(LEVEL_1, (transRec->numParticipants == 1));
  436.  
  437.         stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants));
  438.  
  439.         SM_ASSERT(LEVEL_1, (stl != NULL));
  440.         message.header.params.in.tid = stl->tid;
  441.         serverInfo = stl->serverInfo;
  442.  
  443.         /*
  444.          *    TODO - mention whether logging was turned on. ??
  445.          */
  446.         /* message.body.trans.loggingOn = LogInfo.loggingOn; */
  447.  
  448.         message.body.trans.syncTrans = FALSE;
  449.  
  450.         /* request server to commit the transaction */
  451.         error = callServer(serverInfo, &message, NULL, 0 );
  452.  
  453.         /*
  454.             The server's replies to a commit are :
  455.                 
  456.             esmTRANSDISABLED, (not done - i'm not done with recovery
  457.                                 - try later)
  458.             esmBADTRANSID, (i don't know about this trans so it must
  459.                 have been done already) 
  460.  
  461.             esmTRANSABORTED transaction was aborted during commit.
  462.  
  463.             esmNOTTRANSMASTER, (you can't tell me to do this so I
  464.                             won't - someone else must)
  465.             esmBADCOMMAND (i didn't understand you so it's not been
  466.                            done internal error)
  467.                 
  468.             esmTRANSNOTPREPARED so i ignored this commit request -
  469.                 fail but don't locally do anything
  470.             esmNOERROR (abort/commit done)
  471.  
  472.             If the server got disconnected, the client code can return
  473.                 esmSERVERDIED or esmNOTCONNECTED (doubtful):
  474.                 assume that it was not done and retry
  475.         */
  476.         if (error != esmNOERROR)    {
  477.             switch(sm_errno) {
  478.  
  479.             case esmSERVERDIED:
  480.             case esmNOTCONNECTED:
  481.                 /* might want to try again later */
  482.                 return esmFAILURE;
  483.  
  484.             case esmBADTRANSID:
  485.                 break; /* assume it worked; get rid of tx */
  486.  
  487.             case esmTRANSABORTED:
  488.                 break; /* it failed; keep the tx; user must abort it */
  489.  
  490.             case esmTRANSDISABLED:
  491.                 return esmFAILURE; /* failed; leave tx active */
  492.  
  493.             case esmNOTTRANSMASTER:
  494.             case esmBADCOMMAND:
  495.             case esmTRANSNOTPREPARED: /* should not happen: internal error */
  496.             default: /* don't know what this situation is ! */
  497.                 SM_ERROR(TYPE_FATAL, sm_errno);
  498.             }
  499.         }
  500.     }
  501.     removeServerTransInfo(transRec, NULL);
  502.  
  503.     transRec->clientTransState = T_INACTIVE;    
  504.     transRec->clientTid = NULL_TID;
  505.     transRec->coordTid = NULL_TID;
  506.  
  507.     return esmNOERROR;
  508. }
  509.  
  510.  int
  511. prepareTrans (
  512.     TRANSREC    *transRec,
  513.     VOTE        *vote,
  514.     BOOL        prepareAndCommit
  515. )
  516. {
  517.     MESSAGE                message;
  518.     SERVERADDRTID        serverAddrTid[MAXPARTICIPANTS];
  519.     int                    numParticipants;
  520.     SERVERTRANSREC        *stl;
  521.  
  522.     TRACE(TR_TRANS, TR_LEVEL_1);
  523.     TRPRINT(TR_SM|TR_TRANS|TR_DISTR, TR_LEVEL_1,
  524.             ("prepareTrans: transRec->numParticipants:%d", 
  525.             transRec->numParticipants));
  526.  
  527.     endTrans(T_PREPARED, transRec);
  528.  
  529.     /*
  530.      *    take care of case where we haven't yet chosen a coord
  531.      */
  532.     if (transRec->coordTid == NULL_TID) {
  533.         (void) pickCoord(transRec); /* can't return in error */
  534.     }
  535.  
  536.     /* 
  537.      *  Make sure that we're in sync with all the servers
  538.      *  (which is to say, they've got the last log pages and 
  539.      *  the last data pages).
  540.      *  Do this before we tell the coord to do anything
  541.      *  but as late as possible so that while the pages are
  542.      *  being flushed to the server, we might get something 
  543.      *  else done here.
  544.      */
  545.     io_SyncTrans(transRec, FALSE);
  546.  
  547.     /*
  548.      *    set up the prepare message for the coordinator
  549.      */
  550.     message.header.type = COORD_PREPARE_TRANS;
  551.     message.header.replyRequested = TRUE;
  552.     message.header.params.in.tid = transRec->coordTid;
  553.  
  554.     /*
  555.      *    set up the list of SERVERADDRTIDs to send with the 
  556.      *    prepare message
  557.      */
  558.     for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(transRec->participants)),
  559.         numParticipants = 0;
  560.  
  561.         stl != NULL;
  562.         numParticipants++,
  563.         stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->participants))
  564.         ) {
  565.  
  566.         serverAddrTid[numParticipants].tid = stl->tid;
  567.         serverAddrTid[numParticipants].connectAddr = 
  568.             stl->serverInfo->connectAddr;
  569.     }
  570.  
  571.     SM_ASSERT(LEVEL_1, (transRec->numParticipants == numParticipants));
  572.  
  573.     message.body.prepare.numParticipants = numParticipants;
  574.     message.body.prepare.prepareAndCommit = prepareAndCommit;
  575.  
  576.     /* request server to prepare the transaction */
  577.     if (callServer(transRec->coordInfo, &message, (char *) serverAddrTid , 
  578.         numParticipants * sizeof(SERVERADDRTID))
  579.         != esmNOERROR)    {
  580.  
  581.         /*  esmTRANSDISABLED - could try again 
  582.             esmNOFREESERVERTIDINFO ditto
  583.             esmLOGDISABLED        no log; can't do it now - ditto
  584.             esmBADTRANSID        no dice: better abort
  585.             esmNOTTRANSMASTER    never : TODO FIX THIS ON SERVER
  586.             esmTOOMANYSERVERS    never: better abort
  587.             esmTRANSCOMMITTED    already committed
  588.             esmTRANSABORTED        already aborted
  589.             myriad others        no dice: better abort
  590.         */
  591.         switch(sm_errno) {
  592.         case    esmNOTCONNECTED:
  593.         case    esmSERVERDIED:
  594.         case    esmTRANSDISABLED:
  595.         case    esmNOFREESERVERTIDINFO:
  596.         case    esmLOGDISABLED:
  597.                 /* let user try again later */
  598.                 return esmFAILURE;
  599.  
  600.         case    esmTRANSCOMMITTED:
  601.                 *vote = READVOTE;
  602.                 break;
  603.         case    esmTRANSABORTED:
  604.         default:
  605.                 *vote = NOVOTE; /* kludge */
  606.                 break;
  607.         }
  608.     } else {
  609.         *vote = message.body.vote.vote;
  610.     }
  611.  
  612.     if(*vote == NOVOTE) {
  613.         /* aborted : user must do an abort  */
  614.  
  615.         transRec->clientTransState = T_ABORT;    
  616.         SM_TRANSABORTED(TYPE_USER, esmTRANSNOTPREPARED);
  617.         return esmFAILURE;
  618.  
  619.     } else if(*vote == READVOTE) {
  620.  
  621.         /* committed */
  622.         transRec->clientTransState = T_INACTIVE;    
  623.         transRec->clientTid = NULL_TID;
  624.         transRec->coordTid = NULL_TID;
  625.     }
  626.     /* a prepared tx has no reason to hang onto any of its participants info*/
  627.     removeServerTransInfo(transRec, NULL);
  628.  
  629.     return esmNOERROR;
  630. }
  631.  
  632.  int
  633. abortTrans (
  634.     TRANSREC    *transRec
  635. )
  636.  /*
  637.   *    This routine will be called only in the case of a transaction
  638.   *    which is single server and has not been prepared.
  639.   *    In case there are multiple servers, each will be contacted 
  640.   *    separately using endTransForAllServers() or through
  641.   *    the coordinator using commandTrans()
  642.   */
  643. {
  644.     TRACE(TR_TRANS, TR_LEVEL_1);
  645.  
  646.     endTrans(T_ABORT, transRec);
  647.  
  648.     endTransForAllServers(transRec, ABORT_TRANS);
  649.     transRec->clientTid = NULL_TID;
  650.     transRec->coordTid = NULL_TID;
  651.  
  652.     return esmNOERROR;
  653. }
  654.  
  655.  void
  656. ForEachTransOnServer(
  657.     SERVERINFO     *serverInfo,
  658.     int            nargs,
  659.     void        *f,
  660.     void        *arg1,
  661.     void        *arg2,
  662.     void        *arg3
  663. )
  664. {
  665.     FOREACHFUNC    func = (FOREACHFUNC)f;
  666.     SERVERTRANSREC *stl;
  667.  
  668.     SM_ASSERT(LEVEL_1, (nargs <= 4));
  669.     SM_ASSERT(LEVEL_1, (nargs >= 1));
  670.  
  671.     for(stl = (SERVERTRANSREC *)FIRST_LIST_ELEMENT(&(serverInfo->transList));
  672.         stl!=NULL;
  673.         stl = (SERVERTRANSREC *)NEXT_LIST_ELEMENT(&(stl->transList)) ) {
  674.  
  675.             if ((*func)(stl, arg1, arg2, arg3))
  676.                 /* stop looking if found */
  677.                 break;
  678.     }
  679. }
  680.  
  681. static BOOL
  682. abortTransIfMatches(SERVERTRANSREC *stl, TID tid)
  683. {
  684.     if((tid != NULL_TID) && (stl->tid != tid))
  685.         return FALSE; /* keep looking */
  686.  
  687.     CLIENT_ABORT_TRANS(stl->transRec);
  688.     return TRUE;
  689. }
  690.  
  691. void
  692. serverAbortedTrans(SERVERINFO *serverInfo, TID tid)
  693. {
  694.     ForEachTransOnServer(serverInfo, 2, abortTransIfMatches, (void *)tid, 0, 0);
  695. }
  696.  
  697. #endif __serverTransPool_C__
  698.